Piano notes book, powered by Astro and React.
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 

138 rindas
3.5 KiB

  1. import createVerovioModule from 'verovio/wasm';
  2. import { VerovioToolkit } from 'verovio/esm';
  3. import { readFile, readdir } from 'node:fs/promises';
  4. import { JSDOM } from 'jsdom';
  5. import type {APIRoute, GetStaticPaths} from 'astro';
  6. // @ts-ignore
  7. import tailwindConfigRaw from '../../../tailwind.config.mjs';
  8. const filter = (musicXml: string) => {
  9. const jsdom = new JSDOM(musicXml, { pretendToBeVisual: true, contentType: 'image/svg+xml' });
  10. const win = jsdom.window;
  11. // const win = jsdom.window;
  12. return win.document.documentElement.outerHTML;
  13. };
  14. const processOutput = (xmlData: string) => {
  15. const jsdom = new JSDOM(xmlData, { pretendToBeVisual: true, contentType: 'image/svg+xml' });
  16. const win = jsdom.window;
  17. const [svgElemsRoot, svgElemsMain] = Array.from(win.document.getElementsByTagName('svg'));
  18. if (typeof svgElemsRoot === 'undefined') {
  19. return '';
  20. }
  21. if (typeof svgElemsMain === 'undefined') {
  22. return '';
  23. }
  24. // svgElemsRoot.getAttributeNames().forEach((a) => {
  25. // const attr = svgElemsRoot.getAttribute(a);
  26. // if (!attr) {
  27. // return;
  28. // }
  29. // svgElemsMain.setAttribute(a, attr);
  30. // });
  31. Array.from(svgElemsRoot.children).forEach((h) => {
  32. if (h !== svgElemsMain) {
  33. h.remove();
  34. if (h.tagName.toLowerCase() === 'desc') {
  35. return;
  36. }
  37. if (h.tagName.toLowerCase() === 'style') {
  38. const tailwindConfig = tailwindConfigRaw as any;
  39. h.innerHTML = h.innerHTML.replace(/Times,serif/g, tailwindConfig.theme.fontFamily.body.join(','));
  40. }
  41. if (svgElemsMain.children[0]) {
  42. svgElemsMain.insertBefore(h, svgElemsMain.children[0]);
  43. return;
  44. }
  45. svgElemsMain.appendChild(h);
  46. }
  47. });
  48. Array.from(win.document.getElementsByClassName('pgHead')).forEach(h => {
  49. h.remove();
  50. });
  51. Array.from(win.document.getElementsByClassName('pgFoot')).forEach(h => {
  52. h.remove();
  53. });
  54. Array.from(win.document.getElementsByTagName('defs')).forEach(h => {
  55. h.remove();
  56. if (svgElemsMain) {
  57. if (svgElemsMain.children[0]) {
  58. svgElemsMain.insertBefore(h, svgElemsMain.children[0]);
  59. } else {
  60. svgElemsMain.appendChild(h);
  61. }
  62. }
  63. });
  64. return `<?xml version="1.0" encoding="utf-8"?>${svgElemsMain.outerHTML}`
  65. };
  66. export const GET: APIRoute = async ({ params }) => {
  67. const verovioModule = await createVerovioModule();
  68. const score = await readFile(`public/scores/${params.asset}.musicxml`, 'utf-8');
  69. const verovioToolkit = new VerovioToolkit(verovioModule);
  70. const filteredScore = filter(score);
  71. const isSuccessful = verovioToolkit.loadData(filteredScore);
  72. if (!isSuccessful) {
  73. return new Response(null, { status: 500 });
  74. }
  75. verovioToolkit.setOptions({
  76. breaks: 'none',
  77. font: 'Bravura',
  78. bottomMarginHeader: 0,
  79. bottomMarginArtic: 0,
  80. bottomMarginHarm: 0,
  81. topMarginHarm: 0,
  82. topMarginArtic: 0,
  83. topMarginPgFooter: 0,
  84. pageMarginTop: 0,
  85. pageMarginBottom: 0,
  86. pageMarginRight: 0,
  87. pageMarginLeft: 0,
  88. defaultBottomMargin: 0,
  89. defaultTopMargin: 0,
  90. defaultLeftMargin: 0,
  91. defaultRightMargin: 0,
  92. });
  93. let data: string;
  94. try {
  95. const raw = verovioToolkit.renderToSVG(1)
  96. .replace(/xmlns:mei="(.+?)"/g, '')
  97. .replace(/xlink:/g, '');
  98. data = processOutput(raw);
  99. } catch (err) {
  100. console.error(err);
  101. return new Response(null, { status: 500 });
  102. }
  103. return new Response(
  104. data,
  105. {
  106. headers: {
  107. 'Content-Type': 'image/svg+xml',
  108. },
  109. status: 200,
  110. }
  111. );
  112. };
  113. export const getStaticPaths: GetStaticPaths = async () => {
  114. const files = await readdir('public/scores');
  115. return files
  116. .filter((f) => f.endsWith('.musicxml'))
  117. .map((f) => ({
  118. params: {
  119. asset: f.replace(/\.musicxml/g, ''),
  120. },
  121. }));
  122. };